package top.xxyu.utils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import ch.ethz.ssh2.*;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.util.CollectionUtils;
import top.xxyu.RemoteConnect;
import top.xxyu.dao.ServerLogDao;
import top.xxyu.entity.ServerLog;

public class SSHGanymedUtil {
    private Logger logger = LoggerFactory.getLogger(SSHGanymedUtil.class);
    private String hostname;
    private int port;
    private String username;
    private String password;
    private File pukFile;
    private long taskId;
    private Connection connection;
    private SCPClient scpClient;


    private String windowsSeparator = Matcher.quoteReplacement(File.separator);

    public SSHGanymedUtil(String ip, int _port, String _username,
                          File pukFile) {
        this.hostname = ip;
        this.port = _port;
        this.username = _username;
        this.pukFile = pukFile;
        this.password = "";
    }

    public SSHGanymedUtil(String _hostname, int _port, String _username,
                          String _password) {
        this.hostname = _hostname;
        this.port = _port;
        this.username = _username;
        this.password = _password;
    }

    public SSHGanymedUtil(String _hostname, int _port, String _username,
                          String _password, Long id) {
        this(_hostname, _port, _username, _password);
        this.taskId = id;
    }

    public void login() throws Exception {
        logger.info("start task id is " + taskId);
        // 建立连接
        connection = new Connection(hostname, port);
        try {
        // 连接上
            connection.connect();
        } catch (Exception e) {
            logger.info("error");
            throw new Exception("连接失败");
        }
        try {
        // 进行校验
            boolean isAuthenticated = connection.authenticateWithPassword(
                    username, password);
            logger.info("isAuthenticated = " + isAuthenticated);
            if (isAuthenticated == false)
                throw new IOException("Authentication failed.");
        } catch (Exception e) {
            logger.info("error");
            throw new Exception("UserOrPasswordError");
        }
    }

    public boolean loginPuk() {
        boolean isAuthenticated = false;
        logger.info("start task id is " + taskId);
        // 建立连接
        connection = new Connection(hostname, port);
        // 连接上
        try {
            connection.connect();
        } catch (IOException e) {
            e.printStackTrace();
            logger.info("连接失败");
        }
        try {
            // 进行校验
            isAuthenticated = connection.authenticateWithPassword(
                    username, password);
            logger.info("isAuthenticated = " + isAuthenticated);
//            isAuthenticated = connection.authenticateWithPublicKey(
//                    username, this.pukFile, password);
//            logger.info("isAuthenticated = " + isAuthenticated);
            if (isAuthenticated == false)
                throw new IOException("Authentication failed.");
        } catch (Exception e) {
            logger.error(e.toString());
        }
        return isAuthenticated;
    }

    public String execCommand(final String command) {
        logger.info("start exexCommand");
        final StringBuilder sb = new StringBuilder();
        // 连接的通道
        Session sess = null;
        try {
            // 创建session
            sess = connection.openSession();
            sess.execCommand(command);
            logger.info(command);
            StreamGobbler stdout = new StreamGobbler(sess.getStdout());
            BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
            while(true){
                String line = br.readLine();
                if(line==null) break;
                System.out.println(line);
                sb.append(line);
            }
            logger.info(sb.toString());
        } catch (Throwable e) {
            logger.error(e.toString());
            sb.append(e.toString());
        }finally {
            if(null != sess){
                sess.close();
            }
        }
        return sb.toString();
    }










    public String execCommand2(final String command) {
        logger.info("start exexCommand");
        final StringBuilder sb = new StringBuilder();
        // 连接的通道
        Session sess = null;
        try {
            // 创建session
            sess = connection.openSession();
            // 这句非常重要，开启远程的客户端
//            sess.requestPTY("vt100", 80, 0, 0, 0, null);
//            sess.requestPTY("vt100", 80, 24, 640, 480, null);
//            sess.requestPTY("dumb", 80, 0, 0, 0, null);
//            sess.requestPTY("vt100");
            // 开启后睡眠4秒
//            Thread.sleep(1000);
//             开启终端
//             sess.startShell();
            // 执行命令
            sess.execCommand(command);
            logger.info(command);
            // 起始时间,避免连通性陷入死循环
            long start = System.currentTimeMillis();
            // // 增加timeOut时间
            // sess.waitForCondition(ChannelCondition.TIMEOUT, 5000);
            InputStream stdout = new StreamGobbler(sess.getStdout());
//            BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
//            char[] arr = new char[512];
//            int read;
//            int i = 0;
//            while (true) {
//                // 将结果流中的数据读入字符数组
//                read = br.read(arr, 0, arr.length);
//                // 推延5秒就退出[针对连通性测试会陷入死循环]
//                if (read < 0 || (System.currentTimeMillis() - start) > 5000)
//                    break;
//                // 将结果拼装进StringBuilder
//                sb.append(new String(arr, 0, read));
//                i++;
//            }
            stdout = new StreamGobbler(sess.getStdout());
            BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
            while(true){
                String line = br.readLine();
                if(line==null) break;
                System.out.println(line);
                sb.append(line);
            }

//            logger.info("ExitCode: " + sess.getExitStatus() + "i = " + i);
            logger.info(sb.toString());
        } catch (Throwable e) {
            logger.error(e.toString());
            sb.append(e.toString());
        }finally {
            if(null != sess){
                sess.close();
            }
        }
//        ServerLog serverLog = new ServerLog();
//        serverLog.setId(UUID.randomUUID().toString());
//        serverLog.setIp(hostname);
//        serverLog.setContent("execute:"+command+"  result:"+sb.toString());
//        serverLogDao.save(serverLog);
        return sb.toString();
    }







    public void scpPut(String localFile, String remoteDir) {

        //判断远程服务器文件夹是否存在，若不在，需自动创建 todo
        try {
            remoteDir = remoteDir.replaceAll(windowsSeparator, Matcher.quoteReplacement(File.separator));
            String s = execCommand("md  " + remoteDir);
            System.out.println(s);
            String s1 = localFile.replaceAll(windowsSeparator, Matcher.quoteReplacement(File.separator));
            long length = new File(s1).length();
//            String s = execCommand("del  " + remoteDir+windowsSeparator+new File(s1).getName());
            scpClient.put(s1, remoteDir);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 传输整个目录
     *
     * @param localDirectory
     * @param remoteTargetDirectory
     * @throws IOException
     */
    public void transferDirectory(String localDirectory, String remoteTargetDirectory) throws IOException {
        File dir = new File(localDirectory);
        if (!dir.isDirectory()) {
            throw new RuntimeException(localDirectory + " is not directory");
        }

        String[] files = dir.list();
        for (String file : files) {
            if (file.startsWith(".")) {
                continue;
            }

            String fullName = localDirectory + windowsSeparator + file;
            if (new File(fullName).isDirectory()) {
                String rdir = remoteTargetDirectory + windowsSeparator + file;
                transferDirectory(fullName, rdir);
            } else {
                scpPut(fullName, remoteTargetDirectory);
            }
        }

    }
//    /**
//     * 远程传输单个文件
//     *
//     * @param localFile
//     * @param remoteTargetDirectory
//     * @throws IOException
//     */
//
//    public void transferFile(String localFile, String remoteTargetDirectory) throws IOException {
//        File file = new File(localFile);
//        if (file.isDirectory()) {
//            throw new RuntimeException(localFile + "  is not a file");
//        }
//        String fileName = file.getName();
//        execCommand("mkdir -p " + remoteTargetDirectory);
//
//        SCPClient sCPClient = connection.createSCPClient();
//        SCPOutputStream scpOutputStream = sCPClient.put(fileName, file.length(), remoteTargetDirectory, "0600");
//
//        String content = IOUtils.toString(new FileInputStream(file), StandardCharsets.UTF_8);
//        scpOutputStream.write(content.getBytes());
//        scpOutputStream.flush();
//        scpOutputStream.close();
//    }

    public void initAll() {
        initScpClient();
    }
//    private void initOpenSession() {
//        if (sess == null) {
//            try {
//                sess = connection.openSession();
//                sess.requestPTY("vt100", 80, 0, 0, 0, null);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//    }
    public void initScpClient(){
        if(scpClient == null){
            scpClient = new SCPClient(connection);
        }
    }

    public void closeConnection() {
        logger.info("end task id is " + taskId + "disconnet");
        if (connection != null)
            connection.close();
    }

    public String getHostname() {
        return hostname;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public static void main(String[] args) {
        char[] c = new char[3072];
        for (int i = 0; i < c.length; i++) {
            c[i] = 'a';
        }
        String s = new String(c, 0, 3072);
        System.out.println(s);
    }

    public File getPukFile() {
        return pukFile;
    }

    public void setPukFile(File pukFile) {
        this.pukFile = pukFile;
    }

    public long getTaskId() {
        return taskId;
    }

    public void setTaskId(long taskId) {
        this.taskId = taskId;
    }

    public Connection getConnection() {
        return connection;
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    public SCPClient getScpClient() {
        return scpClient;
    }

    public void setScpClient(SCPClient scpClient) {
        this.scpClient = scpClient;
    }

    public void closeAll() {
        try {
            this.connection.close();

        } catch (Exception e) {
            e.printStackTrace();
            this.connection = null;
        }
    }
}
